/*
 * Copyright (C) 2011-2018 ShenZhen iBOXSaaS Information Technology Co.,Ltd.
 * 
 * All right reserved.
 * 
 * This software is the confidential and proprietary information of iBOXSaaS Company of China.
 * ("Confidential Information"). You shall not disclose such Confidential Information and shall use it only in
 * accordance with the terms of the contract agreement you entered into with iBOXSaaS inc.
 * 
 */

package com.iboxpay.open.auth.center.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.iboxpay.open.common.constants.ParamEnums;
import org.iboxpay.open.common.constants.ResultEnums;
import org.iboxpay.open.common.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.iboxpay.open.auth.center.basedata.BaseData;
import com.iboxpay.open.auth.center.config.AuthCenterConfig;
import com.iboxpay.open.auth.center.enums.MethodEnums;
import com.iboxpay.open.auth.center.service.AuthService;
import com.iboxpay.open.auth.center.service.BizSysAuthService;
import com.iboxpay.open.auth.center.validate.BaseParamValidate;
import com.iboxpay.open.common.db.dao.HealthCheckDao;
import com.iboxpay.open.common.db.entity.AppBaseInfo;
import com.iboxpay.open.common.db.entity.AuthTokenScope;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * AuthController.java
 * 
 * @author xuxiao
 * @date 2018/06/15
 */
@Controller
@Slf4j
public class AuthController {

    @Autowired
    private AuthService authService;

    @Autowired
    private BaseData baseData;

    @Resource(name = "baseParamValidate")
    private BaseParamValidate baseParamValidate;

    @Autowired
    private HealthCheckDao healthCheckDao;

    @Autowired
    private BizSysAuthService bizSysAuthService;

    @Autowired
    private AuthCenterConfig authCenterConfig;

    @RequestMapping(value = "/healthCheck", method = RequestMethod.GET)
    @ResponseBody
    public String healthCheck() {
        healthCheckDao.healthCheck();
        return "{\"resultCode\":\"0\"}";
    }

    @RequestMapping("/refreshBaseData")
    @ResponseBody
    public String refreshBaseData() {
        baseData.init();
        return "{\"resultCode\":\"0\"}";
    }

    @RequestMapping(value = "/user/apply", method = RequestMethod.GET)
    public String authUserApply(@RequestParam Map<String, Object> requestMap, HttpServletRequest request, Model model) {
        baseParamValidate.validate(MethodEnums.authUserConfirm.getCode(), requestMap);
        // 2、用户登录检验
        Map<String, Object> validateResult = bizSysAuthService.userLoginValidate(cookieToMap(request.getCookies()));
        // 3、重定向到登录页面或返回授权申请页面
        String result = MapUtils.getString(validateResult, ParamEnums.resultCode.getCode());
        if (!ResultEnums.success.getCode().equals(result)) {
            log.info("未检测到登录信息，重定向到登录页面。");
            // 重定向到登录页面
            return String.format("redirect:%s", authCenterConfig.getLoginUrl());
        }
        Map<String, AuthTokenScope> scopeMap = new HashMap<>();
        StringTokenizer st = new StringTokenizer(MapUtils.getString(requestMap, ParamEnums.scope.getCode()));
        while(st.hasMoreTokens()) {
            String scope = st.nextToken();
            scopeMap.put(scope, baseData.scopeMap.get(scope));
        }
        // 成功返回申请页面
        model.addAttribute(ParamEnums.scopeMap.getCode(), scopeMap);
        model.addAttribute(ParamEnums.appId.getCode(), requestMap.get(ParamEnums.appId.getCode()));
        model.addAttribute(ParamEnums.state.getCode(), requestMap.get(ParamEnums.state.getCode()));
        model.addAttribute(ParamEnums.confirmUrl.getCode(), authCenterConfig.getAuthConfirmUrl());
        return "authUserApply";
    }

    @RequestMapping(value = "/user/confirm", method = RequestMethod.GET)
    public String authUserConfirm(@RequestParam Map<String, Object> requestMap, HttpServletRequest request) {
        // 1、参数检查
        baseParamValidate.validate(MethodEnums.authUserConfirm.getCode(), requestMap);
        // 2、重定向到登录页面或返回授权申请页面
        Map<String, Object> validateResult = bizSysAuthService.userLoginValidate(cookieToMap(request.getCookies()));
        String result = MapUtils.getString(validateResult, ParamEnums.resultCode.getCode());
        if (!ResultEnums.success.getCode().equals(result)) {
            log.info("未检测到登录信息，重定向到登录页面。");
            // 重定向到登录页面
            return String.format("redirect:%s", authCenterConfig.getLoginUrl());
        }
        // 设置用户id
        String userId = MapUtils.getString(validateResult, ParamEnums.userId.getCode());
        if(StringUtils.isBlank(userId)) {
            throw new BusinessException(ResultEnums.userLoginValidateError);
        }
        requestMap.put(ParamEnums.userId.getCode(), userId);
        // 3、生成authCode
        String authCode = authService.authUserConfirm(requestMap);
        // 4、重定向到第三方页面
        String state = requestMap.get(ParamEnums.state.getCode()) == null ? ""
            : (String)requestMap.get(ParamEnums.state.getCode());
        AppBaseInfo appBaesInfo =
            baseData.appBaseInfoMap.get(Long.valueOf((String)requestMap.get(ParamEnums.appId.getCode())));
        String url = String.format("redirect:%s?%s=%s&%s=%s", appBaesInfo.getRedirectUrl(),
            ParamEnums.authCode.getCode(), authCode, ParamEnums.state.getCode(), state);
        return url;
    }

    @RequestMapping(value = "/user/access_token", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> authUserAccessToken(@RequestParam Map<String, Object> requestMap) {
        // 1、参数检查
        baseParamValidate.validate(MethodEnums.authUserAccessToken.getCode(), requestMap);
        // 2、验证authCode，并生成token
        return authService.authUserAccessToken(requestMap);
    }

    @RequestMapping(value = "/app/access_token", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> authAppAccessToken(@RequestParam Map<String, Object> requestMap) {
        // 1、参数检查
        baseParamValidate.validate(MethodEnums.authAppAccessToken.getCode(), requestMap);
        // 2、生成token
        return authService.authAppAccessToken(requestMap);
    }

    @RequestMapping(value = "/refresh_token", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> authRefreshToken(@RequestParam Map<String, Object> requestMap) {
        // 1、参数检查
        baseParamValidate.validate(MethodEnums.authRefreshToken.getCode(), requestMap);
        // 2、生成token
        return authService.authRefreshToken(requestMap);
    }

    private Map<String, String> cookieToMap(Cookie[] cookies) {
        Map<String, String> cookieMap = new HashMap<>();
        if (cookies != null) {
            for (Cookie entry : cookies) {
                cookieMap.put(entry.getName(), entry.getValue());
            }
        }
        return cookieMap;
    }
}
